
use chess::chessboard::Chessboard;
use super::ChessPlayer;
use super::PieceColor;
use chess::ChessResult;
use chess::Point;

#[derive(Eq, PartialEq)]
pub enum GameStage{
    Waiting, Put, Move, Over
}

///游戏房间，包含两个玩家以及一个棋盘
pub struct GameRoom{
    ///kill count
    kill: u8,

    ///room id
    id: u32,

    ///current player
    current: usize,

    ///room status
    stage: GameStage,

    ///chessboard
    board: Chessboard,

    ///players
    players: [ChessPlayer;2]
}

impl GameRoom{
    pub fn new(id: u32, black: u32, white: u32) -> GameRoom{
        let chessboard = Chessboard::new();
        let pb = ChessPlayer::new(black, 0,PieceColor::Black);
        let pw = ChessPlayer::new(white, 1, PieceColor::White);
        GameRoom{
            kill: 0u8,
            id,
            current: 0,
            stage: GameStage::Put,
            board: chessboard,
            players: [pb, pw]
        }
    }

    pub fn kill_times(&self) -> u8{
        self.kill
    }

    ///房间id
    pub fn id(&self) -> u32{
        self.id
    }

    ///当前执棋人索引
    pub fn current(&self) -> usize{
        self.current
    }

    ///当前执棋人颜色
    pub fn current_player_color(&self) -> &PieceColor{
        self.players[self.current].color()
    }

    ///检查成三
    pub fn check_three(&self, location: u8) -> u8{
        self.board.check_three(&location, self.players[self.current].color())
    }

    pub fn check_stage(&self) -> bool{
        let player_one = &self.players[0];
        let player_two = &self.players[1];
        player_one.is_move() && player_two.is_move()
    }

    ///放子
    /// id: 放子的玩家id
    /// location: 放子的棋子位置
    pub fn put(&mut self, id: u32, location: u8) -> ChessResult{
        let player = &mut self.players[self.current];
        if id != player.id() {
            return ChessResult::Error(203, format!("It is not player {} turn.", id));
        }
        let piece = player.take_piece();
        match piece {
            None => ChessResult::Error(205, format!("The player {} have no more pieces.", id)),
            Some(pc) => self.board.put(&location, pc)
        }
    }

    ///吃子。只能吃对方的未成三的棋子。
    pub fn kill(&mut self, id: u32, location: u8) -> ChessResult{
        let player = &mut self.players[self.current];
        if id != player.id() {
            return ChessResult::Error(106, format!("It is not the active player {}.", id));
        }
        let color = player.opponent_color();
        let three = self.board.check_three(&location, &color);
        if three > 0{
            return ChessResult::Error(225, format!("The location {} you want to kill has bean three", location));
        }
        match self.stage {
            GameStage::Put => self.board.kill_invalid(&location, &color),
            GameStage::Move => self.board.kill_valid(&location, &color),
            _ => ChessResult::Error(105, "Wrong game stage".to_string())
        }
    }

    ///吃了一个棋子，kill值减1
    pub fn kill_ok(&mut self){
        self.kill = self.kill - 1
    }

    ///走棋两个条件：
    /// 1：选择的棋子是自己的
    /// 2：只能走到相邻的空位置
    pub fn pmove(&mut self, id: u32, source: u8, target: u8) -> ChessResult{
        let player = &mut self.players[self.current];
        if id != player.id() {
            return ChessResult::Error(106, format!("It is not the active player {}.", id));
        }
        let color = player.opponent_color();
        let piece = self.board.pickup(&source, &color);
        match piece {
            None => ChessResult::Error(241, format!("The point location you choose to move is invalid: {}", source)),
            Some(p) => {
                if !self.board.is_near(&source, target){
                    return ChessResult::Error(241, format!("Two location not adjacent. source = {}, target = {}", source, target));
                }
                let result = self.board.put(&target, p);
                if let ChessResult::Ok = result{
                    self.board.remove_piece(&source);
                }
                result
            }
        }
    }

    ///检查当前状态对手是否有可以吃的棋子
    pub fn current_can_kill(&self) -> bool{
        self.board.have_single_piece( self.players[self.current].color())
    }

    ///检查棋局状态，如果达到转阶段条件，则转换玩家的阶段标记。
    pub fn player_stage(&mut self){
//        let player = &mut self.players[self.current];
        self.players[self.current].correct_stage();
    }

    ///转换阶段
    pub fn correct_stage(&mut self) -> bool {
        for i in 0..self.players.len(){
            if !self.players[i].is_move(){
                self.stage = GameStage::Move;
                self.board.clear_invalid_marker();
                return false;
            }
        }
        true
    }

    ///返回当前棋盘棋子信息，包括棋子位置，棋子颜色信息。
    pub fn point_array(&self) ->  Vec<Point>{
        self.board.point_array()
    }

    ///有玩家成三，设置成三的数量。最多可以同时成2个三
    pub fn set_kill(&mut self, count: u8){
        if count > 2 {
            error!("Error three count, large than 2: {}", count);
            self.kill = 1u8
        }else {
            self.kill = count;
        }
    }

    ///获取当前玩家的对手玩家的id
    pub fn opponent_id(&self) -> u32{
        let mut index = 0usize;
        if self.current == 0usize{
            index = 1usize;
        }
        self.players[index].opponent()
    }

    ///玩家轮换。将操作权限交给对手。
    pub fn player_rotation(&mut self){
        if self.current == 0{
            self.current = 1;
        }else {
            self.current = 0;
        }
    }

    ///获取当前玩家的下个操作的标识
    pub fn next_operate(&self) -> String{
        if self.players[self.current].is_move(){
            "move".to_string()
        }else {
            "put".to_string()
        }
    }

    ///判断当前玩家是否赢得本局游戏。每次吃子成功后都要检查。
    pub fn is_current_win(&self) -> bool{
        if GameStage::Put == self.stage{
            return false;
        }
        let color = self.players[self.current].opponent_color();
        let count = self.board.board_piece_left(&color);
        count < 3
    }
}